// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.CodeAnalysis;
using System.Collections.Generic;
using System.Runtime.InteropServices.JavaScript;
using System.Threading.Tasks;
using System;
using Xunit;
using Microsoft.Interop.UnitTests;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using Microsoft.CodeAnalysis.Text;
using System.Text;

namespace JSImportGenerator.Unit.Tests
{
    public class Compiles
    {
        public static IEnumerable<object[]> CodeSnippetsToCompile()
        {
            yield return new object[] { CodeSnippets.TrivialClassDeclarations };
            yield return new object[] { CodeSnippets.AllDefault };
            yield return new object[] { CodeSnippets.AllAnnotated };
            yield return new object[] { CodeSnippets.DefaultReturnMarshaler<int>() };
            yield return new object[] { CodeSnippets.DefaultReturnMarshaler<byte>() };
            yield return new object[] { CodeSnippets.DefaultReturnMarshaler<bool>() };
            yield return new object[] { CodeSnippets.DefaultReturnMarshaler<char>() };
            yield return new object[] { CodeSnippets.DefaultReturnMarshaler<string>() };
            yield return new object[] { CodeSnippets.DefaultReturnMarshaler<JSObject>() };
            yield return new object[] { CodeSnippets.DefaultReturnMarshaler<Exception>() };
        }


        [Theory]
        [MemberData(nameof(CodeSnippetsToCompile))]
        public void ValidateSnippets(string source)
        {
            Compilation comp = TestUtils.CreateCompilation(source, allowUnsafe: true);
            TestUtils.AssertPreSourceGeneratorCompilation(comp);

            var newComp = TestUtils.RunGenerators(comp, out var generatorDiags,
                new Microsoft.Interop.JavaScript.JSImportGenerator(),
                new Microsoft.Interop.JavaScript.JSExportGenerator());

            // uncomment for debugging JSTestUtils.DumpCode(source, newComp, generatorDiags);

            Assert.Empty(generatorDiags);

            TestUtils.AssertPostSourceGeneratorCompilation(newComp);
        }

        [Fact]
        public async Task ValidateGeneratedSourceOutput_AllAnnotatedParameters()
        {
            var test = new Test()
            {
                TestState =
                {
                    Sources = { CodeSnippets.AllAnnotated, CodeSnippets.AllAnnotatedExport },
                    GeneratedSources =
                    {
                        (typeof(Microsoft.Interop.JavaScript.JSImportGenerator),
                        "JSImports.g.cs",
                        SourceText.From("""
                            // <auto-generated/>
                            unsafe partial class Basic
                            {
                                [global::System.Diagnostics.DebuggerNonUserCode]
                                internal static partial void Annotated(object a1, long a2, long a3, global::System.Action a4, global::System.Func<int> a5, global::System.Span<byte> a6, global::System.ArraySegment<byte> a7, global::System.Threading.Tasks.Task<object> a8, object[] a9, global::System.DateTime a10, global::System.DateTimeOffset a11, global::System.Threading.Tasks.Task<global::System.DateTime> a12, global::System.Threading.Tasks.Task<global::System.DateTimeOffset> a13, global::System.Threading.Tasks.Task<long> a14, global::System.Threading.Tasks.Task<long> a15)
                                {
                                    if (__signature_Annotated_1583225186 == null)
                                    {
                                        __signature_Annotated_1583225186 = global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding.BindJSFunction("DoesNotExist", null, [global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Discard, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Object, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int52, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.BigInt64, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Action(), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Function(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int32), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Span(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Byte), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.ArraySegment(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Byte), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Object), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Array(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Object), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTime, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTimeOffset, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTime), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTimeOffset), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int52), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.BigInt64)]);
                                    }

                                    {
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument ____arg_exception_native;
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument ____arg_return_native;
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a1_native;
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a2_native;
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a3_native;
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a4_native;
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a5_native;
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a6_native;
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a7_native;
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a8_native;
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a9_native;
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a10_native;
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a11_native;
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a12_native;
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a13_native;
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a14_native;
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a15_native;
                                        // Setup - Perform required setup.
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out ____arg_return_native);
                                        ____arg_return_native.Initialize();
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out ____arg_exception_native);
                                        ____arg_exception_native.Initialize();
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a15_native);
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a14_native);
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a13_native);
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a12_native);
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a11_native);
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a10_native);
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a9_native);
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a8_native);
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a7_native);
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a6_native);
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a5_native);
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a4_native);
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a3_native);
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a2_native);
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a1_native);
                                        // Marshal - Convert managed data to native data.
                                        __a11_native.ToJS(a11);
                                        __a10_native.ToJS(a10);
                                        __a9_native.ToJS(a9);
                                        __a7_native.ToJS(a7);
                                        __a6_native.ToJS(a6);
                                        __a3_native.ToJSBig(a3);
                                        __a2_native.ToJS(a2);
                                        __a1_native.ToJS(a1);
                                        {
                                            // PinnedMarshal - Convert managed data to native data that requires the managed data to be pinned.
                                            __a15_native.ToJS(a15, static (ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __task_result_arg, long __task_result) =>
                                            {
                                                __task_result_arg.ToJSBig(__task_result);
                                            });
                                            __a14_native.ToJS(a14, static (ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __task_result_arg, long __task_result) =>
                                            {
                                                __task_result_arg.ToJS(__task_result);
                                            });
                                            __a13_native.ToJS(a13, static (ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __task_result_arg, global::System.DateTimeOffset __task_result) =>
                                            {
                                                __task_result_arg.ToJS(__task_result);
                                            });
                                            __a12_native.ToJS(a12, static (ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __task_result_arg, global::System.DateTime __task_result) =>
                                            {
                                                __task_result_arg.ToJS(__task_result);
                                            });
                                            __a8_native.ToJS(a8, static (ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __task_result_arg, object __task_result) =>
                                            {
                                                __task_result_arg.ToJS(__task_result);
                                            });
                                            __a5_native.ToJS(a5, static (ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __delegate_arg_arg1, int __delegate_arg1) =>
                                            {
                                                __delegate_arg_arg1.ToJS(__delegate_arg1);
                                            });
                                            __a4_native.ToJS(a4);
                                            __InvokeJSFunction(____arg_exception_native, ____arg_return_native, __a1_native, __a2_native, __a3_native, __a4_native, __a5_native, __a6_native, __a7_native, __a8_native, __a9_native, __a10_native, __a11_native, __a12_native, __a13_native, __a14_native, __a15_native);
                                        }
                                    }

                                    [global::System.Diagnostics.DebuggerNonUserCode]
                                    void __InvokeJSFunction(global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument ____arg_exception_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument ____arg_return_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a1_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a2_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a3_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a4_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a5_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a6_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a7_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a8_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a9_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a10_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a11_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a12_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a13_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a14_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a15_native)
                                    {
                                        global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding.InvokeJS(__signature_Annotated_1583225186, [____arg_exception_native, ____arg_return_native, __a1_native, __a2_native, __a3_native, __a4_native, __a5_native, __a6_native, __a7_native, __a8_native, __a9_native, __a10_native, __a11_native, __a12_native, __a13_native, __a14_native, __a15_native]);
                                    }
                                }

                                static global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding __signature_Annotated_1583225186;
                            }

                            """.ReplaceLineEndings("\r\n"), Encoding.UTF8)),
                        (typeof(Microsoft.Interop.JavaScript.JSExportGenerator),
                        "JSExports.g.cs",
                        SourceText.From("""
                            // <auto-generated/>
                            namespace System.Runtime.InteropServices.JavaScript
                            {
                                [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute]
                                unsafe class __GeneratedInitializer
                                {
                                    [global::System.ThreadStaticAttribute]
                                    static bool initialized;
                                    [global::System.Runtime.CompilerServices.ModuleInitializerAttribute, global::System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute(global::System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods | global::System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicMethods, "System.Runtime.InteropServices.JavaScript.__GeneratedInitializer", "TestProject")]
                                    static internal void __TrimmingPreserve_()
                                    {
                                    }

                                    [global::System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute("__Wrapper_AnnotatedExport_1583225186", "Basic", "TestProject")]
                                    static void __Register_()
                                    {
                                        if (initialized || global::System.Runtime.InteropServices.RuntimeInformation.OSArchitecture != global::System.Runtime.InteropServices.Architecture.Wasm)
                                            return;
                                        initialized = true;
                                        global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding.BindManagedFunction("[TestProject]Basic:AnnotatedExport", 1583225186, [global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Discard, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Object, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int52, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.BigInt64, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Action(), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Function(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int32), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Span(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Byte), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.ArraySegment(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Byte), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Object), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Array(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Object), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTime, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTimeOffset, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTime), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTimeOffset), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int52), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.BigInt64)]);
                                    }
                                }
                            }
                            unsafe partial class Basic
                            {
                                [global::System.Diagnostics.DebuggerNonUserCode]
                                internal static unsafe void __Wrapper_AnnotatedExport_1583225186(global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument* __arguments_buffer)
                                {
                                    __Stub(__arguments_buffer[2], __arguments_buffer[3], __arguments_buffer[4], __arguments_buffer[5], __arguments_buffer[6], __arguments_buffer[7], __arguments_buffer[8], __arguments_buffer[9], __arguments_buffer[10], __arguments_buffer[11], __arguments_buffer[12], __arguments_buffer[13], __arguments_buffer[14], __arguments_buffer[15], __arguments_buffer[16], __arguments_buffer);
                                    [global::System.Diagnostics.DebuggerNonUserCode]
                                    void __Stub(global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a1_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a2_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a3_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a4_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a5_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a6_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a7_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a8_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a9_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a10_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a11_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a12_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a13_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a14_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a15_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument* ____arg_exception_native__param)
                                    {
                                        object a1 = default;
                                        long a2 = default;
                                        long a3 = default;
                                        global::System.Action a4 = default;
                                        global::System.Func<int> a5 = default;
                                        global::System.Span<byte> a6 = default;
                                        global::System.ArraySegment<byte> a7 = default;
                                        global::System.Threading.Tasks.Task<object> a8 = default;
                                        object[] a9 = default;
                                        global::System.DateTime a10 = default;
                                        global::System.DateTimeOffset a11 = default;
                                        global::System.Threading.Tasks.Task<global::System.DateTime> a12 = default;
                                        global::System.Threading.Tasks.Task<global::System.DateTimeOffset> a13 = default;
                                        global::System.Threading.Tasks.Task<long> a14 = default;
                                        global::System.Threading.Tasks.Task<long> a15 = default;
                                        ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument ____arg_exception_native = ref *____arg_exception_native__param;
                                        try
                                        {
                                            // UnmarshalCapture - Capture the native data into marshaller instances in case conversion to managed data throws an exception.
                                            __a11_native.ToManaged(out a11);
                                            __a10_native.ToManaged(out a10);
                                            __a9_native.ToManaged(out a9);
                                            __a7_native.ToManaged(out a7);
                                            __a6_native.ToManaged(out a6);
                                            __a3_native.ToManagedBig(out a3);
                                            __a2_native.ToManaged(out a2);
                                            __a1_native.ToManaged(out a1);
                                            // Unmarshal - Convert native data to managed data.
                                            __a15_native.ToManaged(out a15, static (ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __task_result_arg, out long __task_result) =>
                                            {
                                                __task_result_arg.ToManagedBig(out __task_result);
                                            });
                                            __a14_native.ToManaged(out a14, static (ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __task_result_arg, out long __task_result) =>
                                            {
                                                __task_result_arg.ToManaged(out __task_result);
                                            });
                                            __a13_native.ToManaged(out a13, static (ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __task_result_arg, out global::System.DateTimeOffset __task_result) =>
                                            {
                                                __task_result_arg.ToManaged(out __task_result);
                                            });
                                            __a12_native.ToManaged(out a12, static (ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __task_result_arg, out global::System.DateTime __task_result) =>
                                            {
                                                __task_result_arg.ToManaged(out __task_result);
                                            });
                                            __a8_native.ToManaged(out a8, static (ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __task_result_arg, out object __task_result) =>
                                            {
                                                __task_result_arg.ToManaged(out __task_result);
                                            });
                                            __a5_native.ToManaged(out a5, static (ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __delegate_arg_arg1, out int __delegate_arg1) =>
                                            {
                                                __delegate_arg_arg1.ToManaged(out __delegate_arg1);
                                            });
                                            __a4_native.ToManaged(out a4);
                                            global::Basic.AnnotatedExport(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15);
                                        }
                                        catch (global::System.Exception __arg_exception)
                                        {
                                            ____arg_exception_native.ToJS(__arg_exception);
                                        }
                                    }
                                }
                            }

                            """.ReplaceLineEndings("\r\n"), Encoding.UTF8)),
                    }
                },
            };

            await test.RunAsync();
        }

        [Fact]
        public async Task ValidateGeneratedSourceOutput_Return()
        {
            var test = new Test()
            {
                TestState =
                {
                    Sources = { CodeSnippets.DefaultReturnMarshaler("System.Threading.Tasks.Task<int>") },
                    GeneratedSources =
                    {
                        (typeof(Microsoft.Interop.JavaScript.JSImportGenerator),
                        "JSImports.g.cs",
                        SourceText.From("""
                            // <auto-generated/>
                            unsafe partial class Basic
                            {
                                [global::System.Diagnostics.DebuggerNonUserCode]
                                public static partial global::System.Threading.Tasks.Task<int> Import1()
                                {
                                    if (__signature_Import1_622134597 == null)
                                    {
                                        __signature_Import1_622134597 = global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding.BindJSFunction("DoesNotExist", null, [global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int32)]);
                                    }

                                    {
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument ____arg_exception_native;
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument ____arg_return_native;
                                        global::System.Threading.Tasks.Task<int> __retVal;
                                        global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __retVal_native;
                                        // Setup - Perform required setup.
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out ____arg_return_native);
                                        ____arg_return_native.Initialize();
                                        global::System.Runtime.CompilerServices.Unsafe.SkipInit(out ____arg_exception_native);
                                        ____arg_exception_native.Initialize();
                                        {
                                            __retVal_native = __InvokeJSFunction(____arg_exception_native, ____arg_return_native);
                                        }

                                        // UnmarshalCapture - Capture the native data into marshaller instances in case conversion to managed data throws an exception.
                                        __retVal_native.ToManaged(out __retVal, static (ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __task_result_arg, out int __task_result) =>
                                        {
                                            __task_result_arg.ToManaged(out __task_result);
                                        });
                                        return __retVal;
                                    }

                                    [global::System.Diagnostics.DebuggerNonUserCode]
                                    global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __InvokeJSFunction(global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument ____arg_exception_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument ____arg_return_native)
                                    {
                                        global::System.Span<global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument> __arguments_buffer = [____arg_exception_native, ____arg_return_native];
                                        global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding.InvokeJS(__signature_Import1_622134597, __arguments_buffer);
                                        return __arguments_buffer[1];
                                    }
                                }

                                static global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding __signature_Import1_622134597;
                            }

                            """.ReplaceLineEndings("\r\n"), Encoding.UTF8)),
                        (typeof(Microsoft.Interop.JavaScript.JSExportGenerator),
                        "JSExports.g.cs",
                        SourceText.From("""
                            // <auto-generated/>
                            namespace System.Runtime.InteropServices.JavaScript
                            {
                                [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute]
                                unsafe class __GeneratedInitializer
                                {
                                    [global::System.ThreadStaticAttribute]
                                    static bool initialized;
                                    [global::System.Runtime.CompilerServices.ModuleInitializerAttribute, global::System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute(global::System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods | global::System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicMethods, "System.Runtime.InteropServices.JavaScript.__GeneratedInitializer", "TestProject")]
                                    static internal void __TrimmingPreserve_()
                                    {
                                    }

                                    [global::System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute("__Wrapper_Export1_622134597", "Basic", "TestProject")]
                                    static void __Register_()
                                    {
                                        if (initialized || global::System.Runtime.InteropServices.RuntimeInformation.OSArchitecture != global::System.Runtime.InteropServices.Architecture.Wasm)
                                            return;
                                        initialized = true;
                                        global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding.BindManagedFunction("[TestProject]Basic:Export1", 622134597, [global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int32)]);
                                    }
                                }
                            }
                            unsafe partial class Basic
                            {
                                [global::System.Diagnostics.DebuggerNonUserCode]
                                internal static unsafe void __Wrapper_Export1_622134597(global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument* __arguments_buffer)
                                {
                                    __Stub(__arguments_buffer, __arguments_buffer + 1);
                                    [global::System.Diagnostics.DebuggerNonUserCode]
                                    void __Stub(global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument* ____arg_exception_native__param, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument* __invokeRetValUnmanaged__param)
                                    {
                                        ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument ____arg_exception_native = ref *____arg_exception_native__param;
                                        ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __invokeRetValUnmanaged = ref *__invokeRetValUnmanaged__param;
                                        global::System.Threading.Tasks.Task<int> __invokeRetVal = default;
                                        try
                                        {
                                            __invokeRetVal = global::Basic.Export1();
                                            // Marshal - Convert managed data to native data.
                                            __invokeRetValUnmanaged.ToJS(__invokeRetVal, static (ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __task_result_arg, int __task_result) =>
                                            {
                                                __task_result_arg.ToJS(__task_result);
                                            });
                                        }
                                        catch (global::System.Exception __arg_exception)
                                        {
                                            ____arg_exception_native.ToJS(__arg_exception);
                                        }
                                    }
                                }
                            }

                            """.ReplaceLineEndings("\r\n"), Encoding.UTF8)),
                    }
                },
            };

            await test.RunAsync();
        }

        private sealed class Test : CSharpAnalyzerTest<EmptyDiagnosticAnalyzer, DefaultVerifier>
        {
            public Test()
            {
                ReferenceAssemblies = new ReferenceAssemblies(string.Empty);
                TestState.AdditionalReferences.AddRange(SourceGenerators.Tests.LiveReferencePack.GetMetadataReferences());
            }

            protected override IEnumerable<Type> GetSourceGenerators()
                => [typeof(Microsoft.Interop.JavaScript.JSImportGenerator), typeof(Microsoft.Interop.JavaScript.JSExportGenerator)];
        }
    }
}
